<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Services\LoginAttemptService;
use App\Services\TokenService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

class AuthController extends Controller
{
    protected $tokenService;
    protected $loginAttemptService;

    public function __construct(TokenService $tokenService, LoginAttemptService $loginAttemptService)
    {
        $this->tokenService = $tokenService;
        $this->loginAttemptService = $loginAttemptService;
    }

    /**
     * 用户登录
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {
        // 记录请求信息用于调试
        \Log::info('登录请求开始', [
            'ip' => $request->ip(),
            'method' => $request->method(),
            'url' => $request->fullUrl(),
            'headers' => $request->headers->all(),
            'input' => $request->except(['password']), // 不记录密码
        ]);
        
        try {
            $validator = Validator::make($request->all(), [
                'username' => 'required|string',
                'password' => 'required|string',
            ]);

            if ($validator->fails()) {
                return $this->validationError($validator);
            }

            $identifier = $request->username . '|' . $request->ip();

            // 检查是否被锁定
            try {
                if ($this->loginAttemptService->isLocked($identifier)) {
                    $lockoutTime = $this->loginAttemptService->getLockoutRemainingTime($identifier);
                    $minutes = ceil($lockoutTime / 60);
                    return $this->error("账户已被锁定，请于 {$minutes} 分钟后再试", 423);
                }
            } catch (\Exception $e) {
                \Log::error('检查登录锁定状态失败: ' . $e->getMessage());
                // 如果检查锁定状态失败，继续执行登录流程
            }

            $user = User::where('username', $request->username)->first();

            if (!$user || !Hash::check($request->password, $user->password)) {
                // 记录登录失败
                try {
                    $this->loginAttemptService->recordFailedAttempt($identifier);
                } catch (\Exception $e) {
                    \Log::error('记录登录失败尝试失败: ' . $e->getMessage());
                }
                
                // 记录登录失败日志
                try {
                    if ($user) {
                        \App\Models\LoginLog::create([
                            'user_id' => $user->id,
                            'username' => $request->username,
                            'ip' => $request->ip(),
                            'user_agent' => $request->userAgent(),
                            'status' => 'failed',
                            'message' => '密码错误',
                            'login_at' => now(),
                        ]);
                    } else {
                        \App\Models\LoginLog::create([
                            'user_id' => null,
                            'username' => $request->username,
                            'ip' => $request->ip(),
                            'user_agent' => $request->userAgent(),
                            'status' => 'failed',
                            'message' => '用户不存在',
                            'login_at' => now(),
                        ]);
                    }
                } catch (\Exception $e) {
                    \Log::error('记录登录失败日志失败: ' . $e->getMessage());
                }
                
                try {
                    $remaining = $this->loginAttemptService->remainingAttempts($identifier);
                    return $this->error("用户名或密码错误，剩余尝试次数：{$remaining}", 401);
                } catch (\Exception $e) {
                    return $this->error("用户名或密码错误", 401);
                }
            }

            // 检查用户状态
            if (!$user->isEnabled()) {
                // 记录登录失败日志
                try {
                    \App\Models\LoginLog::create([
                        'user_id' => $user->id,
                        'username' => $user->username,
                        'ip' => $request->ip(),
                        'user_agent' => $request->userAgent(),
                        'status' => 'failed',
                        'message' => '账户已被禁用',
                        'login_at' => now(),
                    ]);
                } catch (\Exception $e) {
                    \Log::error('记录登录失败日志失败: ' . $e->getMessage());
                }
                
                return $this->forbidden('账户已被禁用');
            }

            // 清除登录失败记录
            try {
                $this->loginAttemptService->clearAttempts($identifier);
            } catch (\Exception $e) {
                \Log::error('清除登录失败记录失败: ' . $e->getMessage());
            }

            // 根据用户配置决定Token处理方式
            $loginMode = config('auth.token_login_mode', 'single');
            $token = null;
            
            try {
                if ($loginMode === 'single') {
                    // 单设备登录模式：先删除所有旧token和在线用户记录，然后生成新token
                    try {
                        // 先获取所有旧token，以便删除对应的在线用户记录
                        $oldTokens = $this->tokenService->getUserTokens($user->id);
                        $this->tokenService->removeAll($user->id);
                        
                        // 删除所有旧的在线用户记录
                        if (!empty($oldTokens)) {
                            $oldTokenValues = array_column($oldTokens, 'token');
                            \App\Models\OnlineUser::whereIn('token', $oldTokenValues)->delete();
                        } else {
                            // 如果没有token信息，删除该用户的所有在线记录
                            \App\Models\OnlineUser::where('user_id', $user->id)->delete();
                        }
                    } catch (\Exception $e) {
                        // 删除旧token失败不影响登录，记录日志即可
                        \Log::warning('删除旧Token失败: ' . $e->getMessage(), [
                            'user_id' => $user->id
                        ]);
                        // 仍然尝试删除在线用户记录
                        try {
                            \App\Models\OnlineUser::where('user_id', $user->id)->delete();
                        } catch (\Exception $ex) {
                            \Log::warning('删除旧在线用户记录失败: ' . $ex->getMessage());
                        }
                    }
                    
                    // 生成新token
                    $token = $this->tokenService->generate($user, $request->ip(), $request->userAgent(), true);
                } else {
                    // 多设备登录模式：使用用户个人的设备限制
                    $maxDevices = $user->max_devices ?? config('auth.token_max_devices', 3);
                    
                    try {
                        $tokenCount = $this->tokenService->getTokenCount($user->id);
                        
                        // 如果token数量达到上限，删除最旧的token和对应的在线用户记录
                        if ($tokenCount >= $maxDevices) {
                            try {
                                $oldTokens = $this->tokenService->getUserTokens($user->id);
                                if (!empty($oldTokens)) {
                                    $oldestToken = $oldTokens[0]['token'] ?? null;
                                    $this->tokenService->removeOldestToken($user->id);
                                    // 删除对应的在线用户记录
                                    if ($oldestToken) {
                                        \App\Models\OnlineUser::where('token', $oldestToken)->delete();
                                    }
                                }
                            } catch (\Exception $e) {
                                \Log::warning('删除最旧Token失败: ' . $e->getMessage(), [
                                    'user_id' => $user->id
                                ]);
                            }
                        }
                    } catch (\Exception $e) {
                        // 获取token数量失败不影响登录，记录日志即可
                        \Log::warning('获取Token数量失败: ' . $e->getMessage(), [
                            'user_id' => $user->id
                        ]);
                    }
                    
                    // 尝试复用现有token（如果IP和设备匹配），否则生成新token
                    $token = $this->tokenService->generate($user, $request->ip(), $request->userAgent(), false);
                }
                
                // 验证token是否生成成功
                if (empty($token)) {
                    \Log::error('Token生成失败：返回为空', [
                        'user_id' => $user->id,
                        'login_mode' => $loginMode
                    ]);
                    return $this->error('登录失败：Token生成失败', 500);
                }
            } catch (\Tymon\JWTAuth\Exceptions\JWTException $e) {
                \Log::error('JWT生成失败: ' . $e->getMessage(), [
                    'user_id' => $user->id,
                    'error_type' => get_class($e),
                    'error' => $e->getTraceAsString()
                ]);
                return $this->error('登录失败：Token生成失败，请检查JWT配置', 500);
            } catch (\Exception $e) {
                \Log::error('生成Token失败: ' . $e->getMessage(), [
                    'user_id' => $user->id,
                    'error_type' => get_class($e),
                    'error' => $e->getTraceAsString(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine()
                ]);
                return $this->error('登录失败，请稍后重试', 500);
            }

            // 记录登录成功日志
            try {
                \App\Models\LoginLog::create([
                    'user_id' => $user->id,
                    'username' => $user->username,
                    'ip' => $request->ip(),
                    'user_agent' => $request->userAgent(),
                    'status' => 'success',
                    'message' => '登录成功',
                    'login_at' => now(),
                ]);
            } catch (\Exception $e) {
                \Log::warning('记录登录成功日志失败: ' . $e->getMessage());
            }

            // 记录在线用户（基于token创建或更新，因为token字段是唯一的）
            try {
                // 检查记录是否已存在
                $existingRecord = \App\Models\OnlineUser::where('token', $token)->first();
                
                if ($existingRecord) {
                    // 如果记录已存在（token复用），只更新活动时间和IP等信息，不更新登录时间
                    $existingRecord->update([
                        'user_id' => $user->id,
                        'username' => $user->username,
                        'ip' => $request->ip(),
                        'user_agent' => $request->userAgent(),
                        'last_activity_at' => now(),
                    ]);
                } else {
                    // 如果记录不存在，创建新记录
                    \App\Models\OnlineUser::create([
                        'user_id' => $user->id,
                        'username' => $user->username,
                        'token' => $token,
                        'ip' => $request->ip(),
                        'user_agent' => $request->userAgent(),
                        'login_at' => now(),
                        'last_activity_at' => now(),
                    ]);
                }
            } catch (\Exception $e) {
                // 如果记录在线用户失败，记录日志但不影响登录
                \Log::warning('记录在线用户失败: ' . $e->getMessage(), [
                    'user_id' => $user->id,
                    'token' => $token,
                    'error_type' => get_class($e),
                    'error_message' => $e->getMessage(),
                    'trace' => $e->getTraceAsString()
                ]);
            }

            // 加载用户角色和部门
            $user->load(['roles', 'department']);
            
            // 获取权限服务
            $permissionService = app(\App\Services\PermissionService::class);
            
            // 检查是否是admin角色
            $isAdmin = $user->isAdmin();
            
            // 获取按钮权限（按资源分组）
            $buttonPermissions = $permissionService->getUserButtonPermissions($user);
            
            // 获取角色代码列表
            $roleCodes = $user->roles->pluck('code')->toArray();
            
            // 构建响应数据
            $responseData = [
                'token' => $token,
                'user' => [
                    'id' => $user->id,
                    'username' => $user->username,
                    'nickname' => $user->nickname ?? '',
                    'email' => $user->email ?? '',
                    'avatar' => $user->avatar ?? '',
                    'status' => $user->status,
                    'roles' => $user->roles->pluck('name')->toArray(),
                    'role_codes' => $roleCodes,
                    'is_admin' => $isAdmin,
                    'permissions' => $buttonPermissions,
                    'department' => $user->department ? $user->department->name : null,
                ],
            ];
            
            \Log::info('登录成功，准备返回响应', [
                'user_id' => $user->id,
                'username' => $user->username
            ]);
            
            // 直接返回JSON响应，确保格式正确
            return response()->json([
                'code' => 200,
                'message' => '登录成功',
                'data' => $responseData
            ], 200)->header('Content-Type', 'application/json');
            
        } catch (\Throwable $e) {
            // 捕获所有错误，包括致命错误
            \Log::error('登录过程中发生异常: ' . $e->getMessage(), [
                'exception' => get_class($e),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->except(['password'])
            ]);
            
            // 确保返回JSON格式的错误响应
            return response()->json([
                'code' => 500,
                'message' => config('app.debug') ? $e->getMessage() : '登录失败，请稍后重试',
            ], 500)->header('Content-Type', 'application/json');
        }
    }

    /**
     * 用户登出
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout(Request $request)
    {
        $user = auth()->user();
        
        if ($user) {
            // 移除Token
            $token = $request->bearerToken();
            if ($token) {
                $this->tokenService->remove($token, $user->id);
                
                // 移除对应的在线用户记录（基于token删除，更精确）
                try {
                    \App\Models\OnlineUser::where('token', $token)->delete();
                } catch (\Exception $e) {
                    \Log::warning('删除在线用户记录失败: ' . $e->getMessage());
                    // 如果基于token删除失败，尝试基于user_id删除
                    try {
                        \App\Models\OnlineUser::where('user_id', $user->id)->delete();
                    } catch (\Exception $ex) {
                        \Log::warning('删除在线用户记录失败（fallback）: ' . $ex->getMessage());
                    }
                }
            } else {
                // 如果没有token，删除该用户的所有在线记录
                try {
                    \App\Models\OnlineUser::where('user_id', $user->id)->delete();
                } catch (\Exception $e) {
                    \Log::warning('删除在线用户记录失败: ' . $e->getMessage());
                }
            }
        }

        return $this->success(null, '登出成功');
    }

    /**
     * 获取当前用户信息
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        $user = auth()->user()->load(['roles', 'department']);
        
        // 获取权限服务
        $permissionService = app(\App\Services\PermissionService::class);
        
        // 检查是否是admin角色
        $isAdmin = $user->isAdmin();
        
        // 获取按钮权限（按资源分组）
        $buttonPermissions = $permissionService->getUserButtonPermissions($user);
        
        // 获取角色代码列表
        $roleCodes = $user->roles->pluck('code')->toArray();
        
        return $this->success([
            'id' => $user->id,
            'username' => $user->username,
            'nickname' => $user->nickname ?? '',
            'email' => $user->email ?? '',
            'phone' => $user->phone ?? '',
            'avatar' => $user->avatar ?? '',
            'status' => $user->status,
            'roles' => $user->roles->pluck('name')->toArray(),
            'role_codes' => $roleCodes,
            'is_admin' => $isAdmin,
            'permissions' => $buttonPermissions,
            'department' => $user->department ? $user->department->name : null,
        ], '获取成功');
    }

    /**
     * 刷新Token
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh(Request $request)
    {
        $user = auth()->user();
        $oldToken = $request->bearerToken();
        
        // 生成新Token
        $newToken = $this->tokenService->generate($user, $request->ip(), $request->userAgent());
        
        // 移除旧Token
        if ($oldToken) {
            $this->tokenService->remove($oldToken);
        }
        
        // 更新在线用户Token
        try {
            // 先删除旧token对应的在线用户记录
            if ($oldToken) {
                \App\Models\OnlineUser::where('token', $oldToken)->delete();
            }
            
            // 创建或更新新token对应的在线用户记录
            $onlineUser = \App\Models\OnlineUser::where('token', $newToken)->first();
            if ($onlineUser) {
                $onlineUser->update([
                    'last_activity_at' => now(),
                ]);
                // 更新在线时长
                $onlineUser->updateOnlineDuration();
            } else {
                // 如果不存在，创建新记录
                \App\Models\OnlineUser::create([
                    'user_id' => $user->id,
                    'username' => $user->username,
                    'token' => $newToken,
                    'ip' => request()->ip(),
                    'user_agent' => request()->userAgent(),
                    'login_at' => now(),
                    'last_activity_at' => now(),
                ]);
            }
        } catch (\Exception $e) {
            \Log::warning('更新在线用户Token失败: ' . $e->getMessage());
        }

        return $this->success([
            'token' => $newToken,
        ], '刷新成功');
    }

    /**
     * 忘记密码 - 发送重置密码邮件
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function forgotPassword(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email|exists:users,email',
        ], [
            'email.required' => '邮箱不能为空',
            'email.email' => '邮箱格式不正确',
            'email.exists' => '该邮箱未注册',
        ]);

        if ($validator->fails()) {
            return $this->validationError($validator);
        }

        $status = Password::sendResetLink(
            $request->only('email')
        );

        if ($status === Password::RESET_LINK_SENT) {
            return $this->success(null, '密码重置链接已发送到您的邮箱，请查收');
        }

        return $this->error('发送失败，请稍后重试', 500);
    }

    /**
     * 重置密码
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function resetPassword(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'token' => 'required|string',
            'email' => 'required|email',
            'password' => 'required|string|min:8|confirmed',
        ], [
            'token.required' => '重置令牌不能为空',
            'email.required' => '邮箱不能为空',
            'email.email' => '邮箱格式不正确',
            'password.required' => '密码不能为空',
            'password.min' => '密码长度不能少于8位',
            'password.confirmed' => '两次输入的密码不一致',
        ]);

        if ($validator->fails()) {
            return $this->validationError($validator);
        }

        $status = Password::reset(
            $request->only('email', 'password', 'password_confirmation', 'token'),
            function ($user, $password) {
                $user->password = Hash::make($password);
                $user->save();
            }
        );

        if ($status === Password::PASSWORD_RESET) {
            return $this->success(null, '密码重置成功，请使用新密码登录');
        }

        return $this->error('密码重置失败：' . __($status), 400);
    }
}
